# -*- coding: utf-8 -*-


# 下述类已在底层注册，所以脚本层无须注册，所以这个集合主要是在运算的时候起到排除作用
setInnerExclude = set(["CPlayer", "CNpc", "CDoor", "CMonster", "CAccount"]) 

# 这里主要应用于将下面对象作为远程调用传参的时候，自动将对象转换成对象uid，
# 接收端在根据传过去的格式，提取出uid再通过下面函数获取从内存获取对应的对象，
# 再传进去对应的函数调用（★★★ 主要目的：减少传who、guild对象需要改动脚本层 ★★★）
# todo: 这里还可以继续优化，在框架层整合，无须增加下面配置（通过全局唯一的uuid，可以在框架层抽象这部分）
# 备注：本来在remoteManage模块里面，但是有些对象的创建先于import remoteManage，会报错
if not globals().has_key("gdObjectGetFuncMap"):
	gdObjectGetFuncMap = {}

# 
class CBaseProxyObject(object):
	def __init__(self,iUid=0):
		self._proxyParam = None #有可能同一个代理对象被设置到不同的容器，如Turn对象，所以这里设置成列表
		if not self.boProxy() and not hasattr(self, "iUID"):
			if iUid==0:
				#import scene #如果是常驻场景，统一主从服的常驻场景UID分配方式
				if hasattr(self, "bIsVirtualScene") and not self.IsVirtualScene():
					self.iUID = NewResiScGUID()
				else:
					self.iUID=NewGUID()
			else:
				self.iUID=iUid
			#框架层统一将相关需要包装代理的类，都要注册到底层（CPlayer注册到底层必须要C_CreatePlayerObj接口）
			setClsName = set(map(lambda cls: cls.__name__, self.__class__.mro()))
			if IsMainServer() and not setClsName.intersection(setInnerExclude):
				try:
					#注意：特别是角色上的容器类是挂在角色身上，跟随角色销毁，不能在挂到底层去，否则有内存泄漏
				 	if gdObjectGetFuncMap.has_key(self.__class__.__name__) and not C_FindObject(self.iUID):
						C_CreateObject(self.iUID, self)
				except:
					raise Exception, Language("尝试注册底层异常%0$s",type(self).__name__)

	def UID(self):
		if not self.boProxy():
			return self.iUID
		else:
			token = self.GetProxyToken()
			return token.uid
	#这个函数拷贝UID()原因是，有些功能派生类既然重写了UID，而该获取出来的UID既然是逻辑ID，并非全局唯一ID
	#所以这里的UUID能够表示新框架下的全局唯一UID，但是原来的UID()，则不能，因为它有可能表示角色ID，如：CResume类
	def UUID(self):
		if not self.boProxy():
			return self.iUID
		else:
			token = self.GetProxyToken()
			return token.uid

	#这个函数主要处理一些创建对象兼且创建触发创建代理之后才调用，避免远程找不到对应的proxy对象
	#★★所以尽可能不要在__init__函数里面在触发一些远程调用的东西，例如res.eLooaded+=CFunctor(xxx)
	def AfterProxyCreate(self, *args, **kwds):
		pass

	def Remove(self):
		import remoteManage
		if not self.boProxy(): #真实对象
			try:
				#清理远程代理->本地脚本层->本地底层
				token = self.GetProxyToken()
				#Print(">>> [Remove真实对象], token=%s,self=%s"%(token,type(self)))
				if token: remoteManage.gProxyServerMng.decref(token.addrid, bc=True)
			except:
				LogPyException()
			C_DelObject(self.iUID)
		else:				   #代理对象
			#代理不能主动触发销毁，而是由真身对象决定是否销毁（真身销毁时会广播给代理销毁）
#			token = self.GetProxyToken()
#			#Print(">>> [Remove代理对象], token=%s,self=%s"%(token,type(self)))
#			self._decref()
#			remoteManage.gProxyClientMng.removeProxy(token.uid)
#			C_DelObject(self.iUID)
			pass

	#对象的逻辑id，为了减少改动取名OwnerId
	def OwnerId(self):
		return 0

	#判断当前对象是否代理对象
	def boProxy(self):
		return getattr(self, "_isauto", False)

	def SetProxyToken(self, token):
		setattr(self, "token", token)

	def GetProxyToken(self):
		return getattr(self, "token", None)

	#真实对象逆序请求代理对象相关方法
	def ReverseCall(self, *args, **kwds):
		if not IsMainServer():
			return
		if self.boProxy():
			return
		token = self.GetProxyToken()
		if not token:
			raise Exception(Language("当前对象token异常，token=%0$s,self=%1$s",token,self))
		import remoteManage
		boWait = kwds.get("boWait", False) #标示当前请求是否等待结果返回，默认是不用等待
		if kwds.has_key("boWait"): del kwds["boWait"]
		return remoteManage.dispatch_managerclass(remoteManage.gProxyServerMng,"reversecall",
							(self.UID(),)+args,kwds,nodeidx=-1, nodetype=-1,boWait=boWait,\
							typeid=self.__class__.__name__)

	def SetProxyParams(self, dParam):
		if None == getattr(self, "_proxyParam", None):
			self._proxyParam = []
		if dParam not in self._proxyParam:
			self._proxyParam.append(dParam)

	def GetProxyParams(self):
		return getattr(self, "_proxyParam", None)
		
	def __delattr__(self, key):
		if not self.boProxy():
			try:
				object.__delattr__(self, key)
			except:
				pass